package lex

import (
	"testing"
	"gitcode.com/deyiyangyang/bampoo/tok"
)

func TestNextToken(t *testing.T) {
	input := `(define s "hello world") (display s) "test" symbol123 42 -123 (+ 1 2 3) (* 10 20)`
	
	lexer := New(input)
	
	tests := []struct {
		expectedType    tok.TokenType
		expectedLiteral string
	}{
		{tok.LPAREN, "("},
		{tok.DEFINE, "define"},
		{tok.SYMBOL, "s"},
		{tok.STRING, "hello world"},
		{tok.RPAREN, ")"},
		{tok.LPAREN, "("},
		{tok.DISPLAY, "display"},
		{tok.SYMBOL, "s"},
		{tok.RPAREN, ")"},
		{tok.STRING, "test"},
		{tok.SYMBOL, "symbol123"},
		{tok.INT, "42"},
		{tok.INT, "-123"},
		{tok.LPAREN, "("},
		{tok.PLUS, "+"},
		{tok.INT, "1"},
		{tok.INT, "2"},
		{tok.INT, "3"},
		{tok.RPAREN, ")"},
		{tok.LPAREN, "("},
		{tok.MULTIPLY, "*"},
		{tok.INT, "10"},
		{tok.INT, "20"},
		{tok.RPAREN, ")"},
		{tok.EOF, ""},
	}
	
	for i, tt := range tests {
		token := lexer.NextToken()
		
		if token.Type != tt.expectedType {
			t.Fatalf("tests[%d] - tokentype wrong. expected=%q, got=%q",
				i, tt.expectedType, token.Type)
		}
		
		if token.Literal != tt.expectedLiteral {
			t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q",
				i, tt.expectedLiteral, token.Literal)
		}
	}
}

func TestStringLiterals(t *testing.T) {
	input := `"hello world" "test" "with spaces"`
	
	lexer := New(input)
	
	tests := []struct {
		expectedLiteral string
	}{
		{"hello world"},
		{"test"},
		{"with spaces"},
	}
	
	for i, tt := range tests {
		token := lexer.NextToken()
		
		if token.Type != tok.STRING {
			t.Fatalf("tests[%d] - tokentype wrong. expected=%q, got=%q",
				i, tok.STRING, token.Type)
		}
		
		if token.Literal != tt.expectedLiteral {
			t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q",
				i, tt.expectedLiteral, token.Literal)
		}
	}
}

func TestSymbols(t *testing.T) {
	input := `define display test123 special-chars?`
	
	lexer := New(input)
	
	tests := []struct {
		expectedType    tok.TokenType
		expectedLiteral string
	}{
		{tok.DEFINE, "define"},
		{tok.DISPLAY, "display"},
		{tok.SYMBOL, "test123"},
		{tok.SYMBOL, "special-chars?"},
		{tok.EOF, ""},
	}
	
	for i, tt := range tests {
		token := lexer.NextToken()
		
		if token.Type != tt.expectedType {
			t.Fatalf("tests[%d] - tokentype wrong. expected=%q, got=%q",
				i, tt.expectedType, token.Type)
		}
		
		if token.Literal != tt.expectedLiteral {
			t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q",
				i, tt.expectedLiteral, token.Literal)
		}
	}
}

func TestIntegers(t *testing.T) {
	input := `123 456 789 -42 -100 0`
	
	lexer := New(input)
	
	tests := []struct {
		expectedType    tok.TokenType
		expectedLiteral string
	}{
		{tok.INT, "123"},
		{tok.INT, "456"},
		{tok.INT, "789"},
		{tok.INT, "-42"},
		{tok.INT, "-100"},
		{tok.INT, "0"},
		{tok.EOF, ""},
	}
	
	for i, tt := range tests {
		token := lexer.NextToken()
		
		if token.Type != tt.expectedType {
			t.Fatalf("tests[%d] - tokentype wrong. expected=%q, got=%q",
				i, tt.expectedType, token.Type)
		}
		
		if token.Literal != tt.expectedLiteral {
			t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q",
				i, tt.expectedLiteral, token.Literal)
		}
	}
}

func TestArithmeticOperators(t *testing.T) {
	input := `+ - * /`
	
	lexer := New(input)
	
	tests := []struct {
		expectedType    tok.TokenType
		expectedLiteral string
	}{
		{tok.PLUS, "+"},
		{tok.MINUS, "-"},
		{tok.MULTIPLY, "*"},
		{tok.DIVIDE, "/"},
		{tok.EOF, ""},
	}
	
	for i, tt := range tests {
		token := lexer.NextToken()
		
		if token.Type != tt.expectedType {
			t.Fatalf("tests[%d] - tokentype wrong. expected=%q, got=%q",
				i, tt.expectedType, token.Type)
		}
		
		if token.Literal != tt.expectedLiteral {
			t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q",
				i, tt.expectedLiteral, token.Literal)
		}
	}
}